package com.example.javaproject.thread.juc.threadpool;

import java.util.List;
import java.util.Vector;

/**
 * Description: 实现一个简单的线程池，便于快速理解线程池的原理
 * <br/>Author:  tianjinyong
 * <br/>Date:    2020/7/9 10:38 AM
 *
 * @see <a href="https://blog.csdn.net/zhuguang10/article/details/97131012">实现一个简单的线程池</a>
 */
public class ImpSimpleThreadPool {

    /**
     * 线程池中对象
     */
    static class ThreadPool {

        private static ThreadPool instance;

        /**
         * 空闲线程队列
         */
        private List<PThread> idleThreads;

        /**
         * 已有线程的总数
         */
        private int threadCount;

        /**
         * 线程池是否被shutDown了
         */
        private boolean isShutDown = false;

        private ThreadPool() {
            this.idleThreads = new Vector<>(5);
            this.threadCount = 0;
        }

        public int getCreatedThreadCount() {
            return threadCount;
        }

        public synchronized static ThreadPool getInstance() {
            if (instance == null)
                instance = new ThreadPool();
            return instance;
        }

        /**
         * 将线程放入到线程池中
         *
         * @param repoolingThread
         */
        protected synchronized void repool(PThread repoolingThread) {
            if (!isShutDown || repoolingThread.isIdle) {
                idleThreads.add(repoolingThread);
            } else {
                repoolingThread.shutDown();
            }
        }

        /**
         * 停止线程池中所有的线程
         */
        public synchronized void shutDown() {
            isShutDown = true;
            for (PThread pThread : idleThreads) {
                for (; ; ) {
                    if (pThread.isIdle()) {
                        pThread.shutDown();
                        break;
                    }
                }
            }
        }

        /**
         * 执行任务
         *
         * @param runnable
         */
        public synchronized void start(Runnable runnable) {
            PThread pThread;

            if (idleThreads.size() > 0) { // 如果有空闲线程
                int lastIndex = idleThreads.size() - 1;
                pThread = idleThreads.get(lastIndex);
                idleThreads.remove(pThread);
                threadCount--;
                // 执行任务
                pThread.setTarget(runnable);
            } else {  // 如果没有空闲线程
                threadCount++;
                //创建线程
                pThread = new PThread(runnable, "PThread #" + threadCount, this);
                pThread.start(); // 启动线程
            }
        }

    }

    /**
     * PThread 是永不退出的线程。主体部分是一个无限循环，在手动关闭前用不结束，并一直等待新任务到达
     */
    static class PThread extends Thread {

        private ThreadPool pool;    // 池对象
        private Runnable target;    // 任务
        private boolean isIdle;     // 是否闲置
        private volatile boolean isShutDown; // 是否被关闭

        public PThread(Runnable target, String name, ThreadPool pool) {
            super(name);
            this.pool = pool;
            this.target = target;
        }

        public Runnable getTarget() {
            return target;
        }

        public boolean isIdle() {
            return isIdle;
        }

        @Override
        public void run() {
            while (!isShutDown) {  // 只要没有关闭，则一直循环
                isIdle = false;
                if (target != null) {
                    target.run();
                }

                try {
                    // 当任务执行结束，将线程状态回复到闲置状态
                    isIdle = true;
                    // 将线程重新入池
                    pool.repool(this);

                    synchronized (this) {
                        System.out.println("此时锁对象是" + this);
                        wait(); // 这个时候线程空闲，需要等待新任务的到来，新任务到来唤醒后继续while循环执行任务-->执行完继续等待
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "被唤醒");
            }
            System.out.println(Thread.currentThread().getName() + "运行结束");
        }

        public synchronized void setTarget(Runnable runnable) {
            target = runnable;
            notifyAll();
        }

        public synchronized void shutDown() {
            isShutDown = true;
            notifyAll();
            System.out.println(this + "发起唤醒");
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 1; i++) {
            final int f = i;
            ThreadPool.getInstance().start(new Runnable() {
                @Override
                public void run() {
                    System.out.println("第" + f + "个任务执行,执行它的线程是" + Thread.currentThread());
                }
            });
        }

        ThreadPool.getInstance().shutDown();
    }
}
